#!/usr/bin/env python
# -*- mode: python; coding: utf-8; -*-
# Copyright 1998-2003 Markus Oberhumer <markus@oberhumer.com>
# Copyright 2003 Mt. Hood Playing Card Co.
# Copyright 2005-2011 Skomoroh <skomoroh@users.sourceforge.net>
# Copyright 2010- Jeremy Austin-Bardo <tjaustinbardo@gmail.com>
#
# This file is part of Pysol-UP.
#
# PysolFC is free software: you can redistribute it and/or modify it under
# the terms of the GNU General Public License version 3 of the License as
# published by the Free Software Foundation.
#
# PysolFC is distributed in the hope that it will be useful, but WITHOUT ANY
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
# details.
#
# You should have received a copy of the GNU General Public License along with
# PysolFC. If not, see <http://www.gnu.org/licenses/>.
"""
PysolFC -- Game Quick Play Score Class
======================================
"""

__has_len = lambda ts: int(bool(ts.cards))
__same_suit = lambda n, fs, ts: int(fs.cards[-n]['suit'] == ts.TOPCARD['suit'])
__same_color = lambda n, fs, ts: int(fs.cards[-n]['color'] == ts.TOPCARD['color'])


def Normal(cls, ncards, from_stack, to_stack):
    """
    :function: Normal(ncards:int, from_stack:obj, to_stack: obj) -> int

    - Show preference for ``game.s.reserves`` without cards.
    - Show preference for other groups with cards.

    :param integer ncards: # cards.
    :param object from_stack: Sending pile.
    :param object to_stack: Recieving pile.
    :return: Score.
    :rtype: integer
    """
    if to_stack in cls.s['reserves']:
        return 1000 - __has_len(to_stack)
    return 1001 + __has_len(to_stack)


def Spider(cls, ncards, from_stack, to_stack):
    """
    :function: Spider(ncards:int, from_stack:obj, to_stack: obj) -> int

    - Show preference for ``game.s.reserves`` without cards.
    - Show preference for other groups with cards of |=suit|.

    :param integer ncards: # cards.
    :param object from_stack: Sending pile.
    :param object to_stack: Recieving pile.
    :return: Score.
    :rtype: integer
    """
    if to_stack in cls.s['reserves']:
        return 1000 - __has_len(to_stack)
    if to_stack.cards:
        return __same_suit(ncards, from_stack, to_stack) + 1002
    return 1001


def Tarantula(cls, ncards, from_stack, to_stack):
    """
    :function: Tarantula(ncards:int, from_stack:obj, to_stack: obj) -> int

    - Show preference for ``game.s.reserves`` without cards.
    - Show preference for other groups with cards of |=suit|.

    :param integer ncards: # cards.
    :param object from_stack: Sending pile.
    :param object to_stack: Recieving pile.
    :return: Score.
    :rtype: integer
    """
    if to_stack in cls.s['reserves']:
        return 1000 - __has_len(to_stack)
    if to_stack.cards:
        if __same_suit(ncards, from_stack, to_stack):
            return 1003
        elif __same_color(ncards, from_stack, to_stack):
            return 1002
        return 1001
    return 1000


def LongTail(cls, ncards, from_stack, to_stack):
    """
    :function: LongTail(ncards:int, from_stack:obj, to_stack: obj) -> int

    - Show deference for ``game.s.reserves``.
    - Show preference for other groups with cards of |=suit|.

    :param integer ncards: # cards.
    :param object from_stack: Sending pile.
    :param object to_stack: Recieving pile.
    :return: Score.
    :rtype: integer
    """
    if to_stack in cls.s['reserves']:
        return 1000
    return 1 + Spider(cls, ncards, from_stack, to_stack)


def Montana(cls, ncards, from_stack, to_stack):
    """
    :function: Montana(ncards:int, from_stack:obj, to_stack: obj) -> int

    - Show deference for move leftmost card of row if rank correct

    :param integer ncards: # cards.
    :param object from_stack: Sending pile.
    :param object to_stack: Recieving pile.
    :return: Score.
    :rtype: integer
    """
    if from_stack.cards:
        if (from_stack.id % cls.RSTEP == 0 and
            from_stack.TOPCARD['rank'] == cls.RBASE):
            return -1
        return 1000


def Needle(cls, ncards, from_stack, to_stack):
    """
    :method: Needle(ncards:int, from_stack:obj, to_stack: obj)
          -> int

    - Show deference for ``game.s.reserves``.

    :param integer ncards: # cards.
    :param object from_stack: Sending pile.
    :param object to_stack: Recieving pile.
    :return: Score.
    :rtype: integer
    """
    if to_stack in cls.s['reserves']:
        return 0
    return 1000 + int(bool(to_stack.cards))


def RowStack(cls, ncards, from_stack, to_stack):
    """
    :method: RowStack(ncards:int, from_stack:obj, to_stack: obj)
          -> int

    - Show preference for ``game.s.rows``.

    :param integer ncards: # cards.
    :param object from_stack: Sending pile.
    :param object to_stack: Recieving pile.
    :return: Score.
    :rtype: integer
    """
    return 1000 + int(to_stack in cls.s['rows'])


def RowStackLen(cls, ncards, from_stack, to_stack):
    """
    :method: RowStack(ncards:int, from_stack:obj, to_stack: obj)
          -> int

    - Show preference for pile with cards.

    :param integer ncards: # cards.
    :param object from_stack: Sending pile.
    :param object to_stack: Recieving pile.
    :return: Score.
    :rtype: integer
    """
    return 1000 + int(len(to_stack.cards) > 1)


def BlindRowStack(cls, ncards, from_stack, to_stack):
    """
    :method: RowStack(ncards:int, from_stack:obj, to_stack: obj)
          -> int

    - Show preference for ``game.s.rows`` face_up

    :param integer ncards: # cards.
    :param object from_stack: Sending pile.
    :param object to_stack: Recieving pile.
    :return: Score.
    :rtype: integer
    """
    score = 1000
    if to_stack in cls.s['rows']:
        top_card = to_stack.TOPCARD
        score -= int(bool(top_card))
        score += int(bool(top_card and top_card.face_up))
        return score
    return RowStackLen(cls, ncards, from_stack, to_stack)


def XWasteStack(cls, ncards, from_stack, to_stack):
    """
    :method: RowStack(ncards:int, from_stack:obj, to_stack: obj)
          -> int

    - Show deference for ``game.s.xwastes``

    :param integer ncards: # cards.
    :param object from_stack: Sending pile.
    :param object to_stack: Recieving pile.
    :return: Score.
    :rtype: integer
    """
    if to_stack in cls.s['xwastes']:
        return 0
    return 1 + Normal(cls, ncards, from_stack, to_stack)